package org.hongqi.common.senpec.sys.menu;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hongqi.common.senpec.base.mybatisplus.IBaseEntity;
import org.hongqi.common.senpec.base.mybatisplus.IBaseServiceImpl;
import org.hongqi.common.senpec.base.sevlet.Result;
import org.hongqi.common.senpec.base.spring.redis.RedisService;
import org.hongqi.common.senpec.base.utils.ObjectsUtil;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class MenuServiceImpl extends IBaseServiceImpl<MenuMapper, Menu> implements MenuService {

    private final MenuMapper menuMapper;
    private final RedisService<Menu> redisService;
    private final String redisKey = "sys_menu_list";

    @Override
    public Result<Menu> mySave(Menu entity) {
        //1、查询出所有的menu
        List<Menu> menus = menuMapper.selectList(null);
        if (menus.stream().anyMatch(item -> Objects.equals(item.getName(), entity.getName()))) {
            return Result.error(entity).msg("Name已存在，请修改。");
        }
        entity.setSequence(createSequence(entity.getParent()));
        Collection<Menu> selectedByParent = menuMapper.selectByParent(entity.getParent());
        selectedByParent.forEach(item -> {
            item.setIsTail(false);
            menuMapper.updateById(item);
        });
        entity.setIsTail(true);
        int num = menuMapper.insert(entity);
        if (num == 0) {
            return Result.error(entity);
        } else {
            redisService.deleteKey(redisKey);
            return Result.ok(entity);
        }
    }

    @Override
    public Result<?> myRemoveById(Long id) {
        int num = menuMapper.deleteById(id);
        if (num == 0) {
            return Result.error();
        } else {
            redisService.deleteKey(redisKey);
            return Result.ok();
        }
    }

    @Override
    public Result<Menu> myUpdateById(Menu entity) {
        if (entity.getSequence() == null) {
            entity.setSequence(createSequence(entity.getParent()));
        }
        int num = menuMapper.updateById(entity);
        if (num == 0) {
            return Result.error(entity);
        } else {
            redisService.deleteKey(redisKey);
            return Result.ok(menuMapper.selectById(entity));
        }
    }

    @Override
    public Result<Menu> myGetById(Long id) {
        Menu menu = menuMapper.selectById(id);
        return ObjectsUtil.isNull(menu) ? Result.error(new Menu()) : Result.ok(menu);
    }

    @Override
    public Result<Collection<Menu>> myListTree(Menu entity) {
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, 0L);
        lambdaQueryWrapper.orderByAsc(Menu::getSequence);
        List<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        menus.forEach(item -> item.setChildren(myListByPid(item.getId())));
        return Result.ok(menus);
    }

    @Override
    public Collection<Menu> myListByPid(Long pid) {
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, pid);
        lambdaQueryWrapper.orderByAsc(Menu::getSequence);
        Collection<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        menus.forEach(item -> item.setChildren(myListByPid(item.getId())));
        return menus;
    }

    @Override
    public Collection<Menu> myListMenusExcludeButtonByPid(Long pid) {
        //1、查找父元素为pid且类型不为button的menu，包括subMenu和item
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, pid);
        lambdaQueryWrapper.ne(Menu::getType, "button");
        lambdaQueryWrapper.orderByAsc(Menu::getSequence);
        Collection<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        //2、为每一个菜单设置子菜单（递归调用）
        menus.forEach(item -> item.setChildren(myListMenusExcludeButtonByPid(item.getId())));
        return menus;
    }

    @Override
    public Result<Collection<Menu>> myListMenuButtonsByParentIdAndRoleId(Long pid, Long rid) {
        Collection<Menu> menuList = menuMapper.selectMenusByRoleId(rid);
        if (menuList.size() == 0) {
            return Result.ok(null);
        }
        Collection<Long> menuIdList = menuList.stream().map(IBaseEntity::getId).toList();
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, pid);
        lambdaQueryWrapper.eq(Menu::getType, "button");
        lambdaQueryWrapper.in(Menu::getParent, menuIdList);
        lambdaQueryWrapper.orderByAsc(Menu::getSequence);
        Collection<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        return Result.ok(menus);
    }

    @Override
    public Result<Collection<Menu>> myListTreeWithoutButton() {
        //1、查询所有的一级菜单
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, 0L);
        lambdaQueryWrapper.orderByAsc(Menu::getSequence);
        List<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        //2、为每一个一级菜单设置子菜单
        menus.forEach(item -> item.setChildren(myListMenusExcludeButtonByPid(item.getId())));
        return Result.ok(menus);
    }

    @Override
    public Result<Collection<Menu>> myListMenusByRoleId(Long roleId) {
        return Result.ok(menuMapper.selectMenusByRoleId(roleId));
    }

    @Override
    public Collection<Menu> myListMenusByParent(Long pid) {
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, pid);
        List<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        List<Menu> menuList = new ArrayList<>(menus);
        menus.forEach(menu -> menuList.addAll(myListMenusByParent(menu.getId())));
        return menuList;
    }

    @Override
    public Result<?> myUpdateMenuIdsByRoleId(Long roleId, Long currentMenuId, Collection<Long> menuIds) {
        //1、删除角色拥有的所有非button类型的menu
        menuMapper.deleteMenuNotButtonIdsByRoleId(roleId);
        //2、将所有的被选中的非button类型的menu增加的表中
        menuIds.forEach(menuId -> menuMapper.insertMenuIdByRoleId(roleId, menuId));
        //3、判断当前节点在点击后是否被选中
        boolean currentMenuIdStatus = menuIds.contains(currentMenuId);
        //4、如果当前节点在操作后不被选中，则删除该节点或者所有其子节点对应的button，如果被选中，不做任何操作。
        if (!currentMenuIdStatus) {
            Collection<Menu> menus = this.myListMenusByParent(currentMenuId);
            List<Long> buttonIds = menus.stream().filter(menu -> Objects.equals(menu.getType(), "button")).map(IBaseEntity::getId).toList();
            buttonIds.forEach(buttonId -> menuMapper.deleteMenuIdByRoleId(roleId, buttonId));
        }
        return Result.ok(null);
    }

    @Override
    public Result<?> myDeleteMenuIdsByRoleId(Long roleId) {
        menuMapper.deleteMenuIdsByRoleId(roleId);
        return Result.ok();
    }

    @Override
    public Result<Collection<Menu>> myListMenusForNavy(Long userId) {
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getParent, 0L);
        List<Menu> menus = menuMapper.selectList(lambdaQueryWrapper);
        List<Menu> list = menus.stream().filter(menu -> Objects.equals(menu.getType(), "item")).toList();
        List<Menu> menuList = new ArrayList<>(list);
        menus.forEach(menu -> menu.setChildren(myListMenusByParentAndUserId(menu.getId(), userId)));
        menus = menus.stream().filter(menu -> menu.getChildren().size() != 0).toList();
        menuList.addAll(menus);
        menuList.forEach(item -> {
            item.setFullPath(createFullPath(item.getId()).toString());
            if (Objects.equals(item.getType(), "subMenu")) {
                item.setRedirect(item.getChildren().stream().findFirst().orElseThrow().getFullPath());
            }
        });
        return Result.ok(menuList.stream().sorted(Comparator.comparing(Menu::getSequence)).toList());
    }

    @Override
    public Collection<Menu> myListMenusByParentAndUserId(Long parent, Long userId) {
        Collection<Menu> menuItemsByUserId = menuMapper.selectMenuItemsByUserId(userId);
        List<Long> menuItemIdsByUserId = menuItemsByUserId.stream().map(IBaseEntity::getId).toList();
        List<Menu> menus = menuMapper.selectList(null);
        //查询所有userId拥有的item类型菜单并加入道返回对象
        List<Menu> listMenuItems = menus.stream()//
                .filter(menu -> Objects.equals(menu.getParent(), parent))//
                .filter(menu -> menuItemIdsByUserId.contains(menu.getId()))//
                .toList();
        Collection<Menu> menuList = new ArrayList<>(listMenuItems);

        //查询所有类型为submenu的菜单
        List<Menu> listSubMenus = menus.stream()//
                .filter(menu -> Objects.equals(menu.getParent(), parent))//
                .filter(menu -> Objects.equals(menu.getType(), "subMenu"))//
                .toList();
        for (Menu listMenuItem : listSubMenus) {
            listMenuItem.setChildren(myListMenusByParentAndUserId(listMenuItem.getId(), userId));
        }
        listSubMenus = listSubMenus.stream().filter(menu -> menu.getChildren().size() != 0).toList();
        menuList.addAll(listSubMenus);
        menuList.forEach(item -> {
            item.setFullPath(createFullPath(item.getId()).toString());
            if (Objects.equals(item.getType(), "subMenu")) {
                item.setRedirect(item.getChildren().stream().map(Menu::getFullPath).findFirst().orElseThrow());
            }
        });
        return menuList.stream().sorted(Comparator.comparing(Menu::getSequence)).toList();
    }

    @Override
    public Result<Menu> myUpdateMenuButtonIdByRoleId(Long roleId, Long buttonId) {
        Collection<Menu> menus = menuMapper.selectMenusByRoleId(roleId);
        boolean match = menus.stream().anyMatch(menu -> Objects.equals(menu.getId(), buttonId));
        if (match) {
            menuMapper.deleteMenuIdByRoleId(roleId, buttonId);
        } else {
            menuMapper.insertMenuIdByRoleId(roleId, buttonId);
        }
        return Result.ok();
    }

    @Override
    public Result<Collection<String>> myListMenuButtonIdsByRoleIdAndParent(Long roleId, Long parentId) {
        Collection<Menu> menus = menuMapper.selectMenusByRoleId(roleId);
        List<String> menuIdList = menus.stream()//
                .filter(menu -> Objects.equals(menu.getParent(), parentId))//
                .filter(menu -> Objects.equals(menu.getType(), "button"))//
                .sorted(Comparator.comparing(Menu::getSequence))//
                .map(Menu::getTitle)//
                .toList();
        return Result.ok(menuIdList);
    }

    @Override
    public Result<Menu> myUpdateMenuSequence(Long id, String direction) {

        Menu menu = menuMapper.selectById(id);
        Collection<Menu> menus = menuMapper.selectByParent(menu.getParent());
        Integer currentSequence = menu.getSequence();
        if (menus.size() == 1) {
            return Result.ok(new Menu()).msg("顺序没有变化。");
        }

        if (Objects.equals(direction, "up")) {
            if (menu.getSequence() > 1) {
                Menu lastMenu = menus.stream().filter(item -> item.getSequence() == menu.getSequence() - 1).findFirst().orElseThrow();
                menu.setSequence(currentSequence - 1);
                lastMenu.setSequence(currentSequence);
                if (currentSequence == menus.size()) {
                    menu.setIsTail(false);
                    lastMenu.setIsTail(true);
                }
                menuMapper.updateById(menu);
                menuMapper.updateById(lastMenu);
            } else {
                return Result.ok(new Menu()).msg("顺序没有变化。");
            }
        }

        if (Objects.equals(direction, "down")) {
            if (menus.size() > menu.getSequence()) {
                Menu nextMenu = menus.stream().filter(item -> item.getSequence() == menu.getSequence() + 1).findFirst().orElseThrow();
                menu.setSequence(menu.getSequence() + 1);
                nextMenu.setSequence(nextMenu.getSequence() - 1);
                if (currentSequence + 1 == menus.size()) {
                    menu.setIsTail(true);
                    nextMenu.setIsTail(false);
                }
                menuMapper.updateById(menu);
                menuMapper.updateById(nextMenu);
            } else {
                return Result.ok(new Menu()).msg("顺序没有变化。");
            }
        }
        return Result.ok(menuMapper.selectById(id));
    }

    @Override
    public Integer createSequence(Long id) {
        Integer maxSequence = menuMapper.selectMaxSequenceByParent(id);
        if (maxSequence == null) {
            return 1;
        }
        return maxSequence + 1;
    }

    @Override
    public StringBuilder createFullPath(Long id) {
        StringBuilder path = new StringBuilder();
        Menu menu = menuMapper.selectById(id);
        path.append("/").append(menu.getName());
        if (menu.getParent() != 0) {
            path = createFullPath(menu.getParent()).append(path);
        }
        return path;
    }

    @Override
    public Result<Collection<String>> myListAuthoritiesByUserId(Long userId) {
        Collection<String> menus = menuMapper.selectAuthoritiesByUserId(userId);
        menus.addAll(menuMapper.selectRoleNamesByUserId(userId));
        return Result.ok(menus);
    }

    @Override
    public Result<Collection<String>> myListAuthoritiesByUsername(String username) {
        Collection<String> menus = menuMapper.selectAuthoritiesByUsername(username);
        menus.addAll(menuMapper.selectRoleNamesByUsername(username));
        return Result.ok(menus);
    }

}
